package group.sicher.core.exception.advice;


import group.sicher.core.exception.ResponseException;
import group.sicher.core.exception.base.ErrorCode;
import group.sicher.core.exception.base.SicherErrorCode;
import group.sicher.core.log.LogManagerUtils;
import org.slf4j.Logger;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.regex.Pattern;

/**
 * description:
 * mvc 返回值统一异常处理 通知器 Handler的实现类
 * 拦截所有异常，针对异常类型做统一的处理
 * author:dengjinde
 * date:2019/3/18
 */
@ControllerAdvice
public class SicherExceptionHandlerAdvice {

    private static Logger logger = LogManagerUtils.getLogger(SicherExceptionHandlerAdvice.class);


    /**
     * 处理请求时的异常
     *
     * @param request
     * @param response
     * @param ex
     * @return
     */
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Object controllerExceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception ex) {

        String message = SicherErrorCode.DEFAULT_ERROR.desc();
        ErrorCode errorCode = SicherErrorCode.DEFAULT_ERROR;
        Object data = null;

        //自定义异常捕获处理
        if (ResponseException.class.isAssignableFrom(ex.getClass())) {
            ResponseException responseException = (ResponseException) ex;
            printResponseExceptionLog(responseException, ex);
            return responseException.transferResponse();
        }

        //java常规异常的捕获处理
        if (ex instanceof MissingServletRequestParameterException) {
            MissingServletRequestParameterException exception = (MissingServletRequestParameterException) ex;
            message = "必填 " + exception.getParameterType() + "类型参数 '" + exception.getParameterName() + "' 不存在";
        } else if (ex instanceof EmptyResultDataAccessException) {
            EmptyResultDataAccessException exception = (EmptyResultDataAccessException) ex;
            String pattern = "No class.*with.*exists!.*";
            boolean isMatch = Pattern.matches(pattern, ex.getMessage());
            if (isMatch) {
                message = "数据不存在，请确认";
            }
        } else {
            if (null != ex.getMessage()) {
                message = "系统异常，联系管理员";
            }
        }
        ResponseException responseException = new ResponseException(SicherErrorCode.DEFAULT_ERROR, message);
        printResponseExceptionLog(responseException, ex);
        if (logger.isDebugEnabled()) {
            ex.printStackTrace();
        }
        return responseException.transferResponse();
    }


    /**
     * 对springMvc的参数校验 Validated
     * 异常做统一的处理
     * 处理成友好的展示方式(原生展示很不友好)
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(BindException.class)
    @ResponseBody
    public Object handleBindException(BindException ex) {
        FieldError fieldError = ex.getBindingResult().getFieldError();
        //fixme 数据还未写入
        ResponseException responseException = new ResponseException(SicherErrorCode.DEFAULT_ERROR, fieldError.getField() + fieldError.getDefaultMessage());
        printResponseExceptionLog(responseException, ex);
        return responseException.transferResponse();
    }

    /**
     * 对springMvc的参数校验 Validated
     * 异常做统一的处理
     * 处理成友好的展示方式(原生展示很不友好)
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
        FieldError fieldError = ex.getBindingResult().getFieldError();
        ResponseException responseException = new ResponseException(SicherErrorCode.DEFAULT_ERROR, fieldError.getField() + fieldError.getDefaultMessage());
        printResponseExceptionLog(responseException, ex);
        return responseException.transferResponse();
    }

    /**
     * 错误日志
     *
     * @param responseException
     */
    private void printResponseExceptionLog(ResponseException responseException, Exception ex) {
        if (responseException.getCause() == null) {
            logger.error(String.format("######ErrorCode: [%s],message: [%s]#######", responseException.getCode().code(), responseException.getMessage()));
        } else {
            logger.error(String.format("######ErrorCode: [%s],message: [%s]#######", responseException.getCode().code(), responseException.getMessage()), responseException);
        }
        logger.error(String.format("######ErrorCode: [%s],message: [%s]#######", responseException.getCode().code(), responseException.getMessage()), ex);
    }
}
